/*
 * Copyright 2017-Present, Redis Ltd. and Contributors
 * All rights reserved.
 *
 * Licensed under the MIT License.
 *
 * This file contains contributions from third-party contributors
 * licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.lettuce.core.api.async;

import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.List;

import io.lettuce.core.*;
import io.lettuce.core.annotations.Experimental;
import io.lettuce.core.output.KeyStreamingChannel;
import io.lettuce.core.output.ValueStreamingChannel;

/**
 * Asynchronous executed commands for Keys (Key manipulation/querying).
 *
 * @param <K> Key type.
 * @param <V> Value type.
 * @author Mark Paluch
 * @since 4.0
 * @generated by io.lettuce.apigenerator.CreateAsyncApi
 */
public interface RedisKeyAsyncCommands<K, V> {

    /**
     * Copy the value stored at the source key to the destination key.
     *
     * @param source the source.
     * @param destination the destination.
     * @return Boolean integer-reply specifically: {@code true} if source was copied. {@code false} if source was not copied.
     * @since 6.1
     */
    RedisFuture<Boolean> copy(K source, K destination);

    /**
     * Copy the value stored at the source key to the destination key.
     *
     * @param source the source.
     * @param destination the destination.
     * @param copyArgs the copyArgs.
     * @return Boolean integer-reply specifically: {@code true} if source was copied. {@code false} if source was not copied.
     * @since 6.1
     */
    RedisFuture<Boolean> copy(K source, K destination, CopyArgs copyArgs);

    /**
     * Delete one or more keys.
     *
     * @param keys the keys.
     * @return Long integer-reply The number of keys that were removed.
     */
    RedisFuture<Long> del(K... keys);

    /**
     * Delete the specified key if the compare condition matches.
     *
     * @param key the key.
     * @param compareCondition the compare condition, must not be {@code null}.
     * @return Long integer-reply the number of keys that were removed.
     *
     * @since 7.1
     */
    @Experimental
    RedisFuture<Long> delex(K key, CompareCondition<V> compareCondition);

    /**
     * Return the XXH3 64-bit digest of the string value stored at a key as a 16-character hex string.
     *
     * @param key the key.
     * @return String bulk-string-reply the hex digest of the key's value, or {@code null} when {@code key} does not exist.
     *
     * @since 7.1
     */
    @Experimental
    RedisFuture<String> digestKey(K key);

    /**
     * Unlink one or more keys (non blocking DEL).
     *
     * @param keys the keys.
     * @return Long integer-reply The number of keys that were removed.
     */
    RedisFuture<Long> unlink(K... keys);

    /**
     * Return a serialized version of the value stored at the specified key.
     *
     * @param key the key.
     * @return byte[] bulk-string-reply the serialized value.
     */
    RedisFuture<byte[]> dump(K key);

    /**
     * Determine how many keys exist.
     *
     * @param keys the keys.
     * @return Long integer-reply specifically: Number of existing keys.
     */
    RedisFuture<Long> exists(K... keys);

    /**
     * Set a key's time to live in seconds.
     *
     * @param key the key.
     * @param seconds the seconds type: long.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set.
     */
    RedisFuture<Boolean> expire(K key, long seconds);

    /**
     * Set a key's time to live in seconds.
     *
     * @param key the key.
     * @param seconds the seconds type: long.
     * @param expireArgs the expiry arguments.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set.
     * @since 6.2
     */
    RedisFuture<Boolean> expire(K key, long seconds, ExpireArgs expireArgs);

    /**
     * Set a key's time to live in seconds.
     *
     * @param key the key.
     * @param seconds the seconds.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set.
     * @since 6.1
     */
    RedisFuture<Boolean> expire(K key, Duration seconds);

    /**
     * Set a key's time to live in seconds.
     *
     * @param key the key.
     * @param seconds the seconds.
     * @param expireArgs the expiry arguments.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set.
     * @since 6.2
     */
    RedisFuture<Boolean> expire(K key, Duration seconds, ExpireArgs expireArgs);

    /**
     * Set the expiration for a key as a UNIX timestamp.
     *
     * @param key the key.
     * @param timestamp the timestamp type: posix time.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set (see: {@code EXPIRE}).
     */
    RedisFuture<Boolean> expireat(K key, long timestamp);

    /**
     * Set the expiration for a key as a UNIX timestamp.
     *
     * @param key the key.
     * @param timestamp the timestamp type: posix time.
     * @param expireArgs the expiry arguments.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set (see: {@code EXPIRE}).
     * @since 6.2
     */
    RedisFuture<Boolean> expireat(K key, long timestamp, ExpireArgs expireArgs);

    /**
     * Set the expiration for a key as a UNIX timestamp.
     *
     * @param key the key.
     * @param timestamp the timestamp type: posix time.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set (see: {@code EXPIRE}).
     */
    RedisFuture<Boolean> expireat(K key, Date timestamp);

    /**
     * Set the expiration for a key as a UNIX timestamp.
     *
     * @param key the key.
     * @param timestamp the timestamp type: posix time.
     * @param expireArgs the expiry arguments.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set (see: {@code EXPIRE}).
     * @since 6.2
     */
    RedisFuture<Boolean> expireat(K key, Date timestamp, ExpireArgs expireArgs);

    /**
     * Set the expiration for a key as a UNIX timestamp.
     *
     * @param key the key.
     * @param timestamp the timestamp type: posix time.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set (see: {@code EXPIRE}).
     * @since 6.1
     */
    RedisFuture<Boolean> expireat(K key, Instant timestamp);

    /**
     * Set the expiration for a key as a UNIX timestamp.
     *
     * @param key the key.
     * @param timestamp the timestamp type: posix time.
     * @param expireArgs the expiry arguments.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set (see: {@code EXPIRE}).
     * @since 6.2
     */
    RedisFuture<Boolean> expireat(K key, Instant timestamp, ExpireArgs expireArgs);

    /**
     * Get the time to live for a key in as unix timestamp in seconds.
     *
     * @param key the key.
     * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns {@code -1} if
     *         the key exists but has no associated expiration time. The command returns {@code -2} if the key does not exist.
     * @since 6.2
     */
    RedisFuture<Long> expiretime(K key);

    /**
     * Find all keys matching the given pattern.
     *
     * @param pattern the pattern type.
     * @return List&lt;K&gt; array-reply list of keys matching {@code pattern}.
     */
    RedisFuture<List<K>> keys(String pattern);

    /**
     * Find all keys matching the given pattern (legacy overload).
     *
     * @param pattern the pattern type: patternkey (pattern).
     * @return List&lt;K&gt; array-reply list of keys matching {@code pattern}.
     * @deprecated Use {@link #keys(String)} instead. This legacy overload will be removed in a later version.
     */
    @Deprecated
    RedisFuture<List<K>> keysLegacy(K pattern);

    /**
     * Find all keys matching the given pattern.
     *
     * @param channel the channel.
     * @param pattern the pattern type.
     * @return Long array-reply list of keys matching {@code pattern}.
     */
    RedisFuture<Long> keys(KeyStreamingChannel<K> channel, String pattern);

    /**
     * Find all keys matching the given pattern (legacy overload).
     *
     * @param channel the channel.
     * @param pattern the pattern.
     * @return Long array-reply list of keys matching {@code pattern}.
     * @deprecated Use {@link #keys(KeyStreamingChannel, String)} instead. This legacy overload will be removed in a later
     *             version.
     */
    @Deprecated
    RedisFuture<Long> keysLegacy(KeyStreamingChannel<K> channel, K pattern);

    /**
     * Atomically transfer a key from a Redis instance to another one.
     *
     * @param host the host.
     * @param port the port.
     * @param key the key.
     * @param db the database.
     * @param timeout the timeout in milliseconds.
     * @return String simple-string-reply The command returns OK on success.
     */
    RedisFuture<String> migrate(String host, int port, K key, int db, long timeout);

    /**
     * Atomically transfer one or more keys from a Redis instance to another one.
     *
     * @param host the host.
     * @param port the port.
     * @param db the database.
     * @param timeout the timeout in milliseconds.
     * @param migrateArgs migrate args that allow to configure further options.
     * @return String simple-string-reply The command returns OK on success.
     */
    RedisFuture<String> migrate(String host, int port, int db, long timeout, MigrateArgs<K> migrateArgs);

    /**
     * Move a key to another database.
     *
     * @param key the key.
     * @param db the db type: long.
     * @return Boolean integer-reply specifically:.
     */
    RedisFuture<Boolean> move(K key, int db);

    /**
     * Returns the kind of internal representation used in order to store the value associated with the {@code key}.
     *
     * @param key the key.
     * @return String.
     */
    RedisFuture<String> objectEncoding(K key);

    /**
     * Returns the logarithmic access frequency counter of the object stored at the specified {@code key}.
     *
     * @param key the key.
     * @return Long.
     * @since 6.1
     */
    RedisFuture<Long> objectFreq(K key);

    /**
     * Returns the number of seconds since the object stored at the specified key is idle (not requested by read or write
     * operations).
     *
     * @param key the key.
     * @return number of seconds since the object stored at the specified key is idle.
     */
    RedisFuture<Long> objectIdletime(K key);

    /**
     * Returns the number of references of the value associated with the specified key.
     *
     * @param key the key.
     * @return Long.
     */
    RedisFuture<Long> objectRefcount(K key);

    /**
     * Remove the expiration from a key.
     *
     * @param key the key.
     * @return Boolean integer-reply specifically:
     *
     *         {@code true} if the timeout was removed. {@code false} if {@code key} does not exist or does not have an
     *         associated timeout.
     */
    RedisFuture<Boolean> persist(K key);

    /**
     * Set a key's time to live in milliseconds.
     *
     * @param key the key.
     * @param milliseconds the milliseconds type: long.
     * @return integer-reply, specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not exist or
     *         the timeout could not be set.
     */
    RedisFuture<Boolean> pexpire(K key, long milliseconds);

    /**
     * Set a key's time to live in milliseconds.
     *
     * @param key the key.
     * @param milliseconds the milliseconds type: long.
     * @param expireArgs the expiry arguments.
     * @return integer-reply, specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not exist or
     *         the timeout could not be set.
     * @since 6.2
     */
    RedisFuture<Boolean> pexpire(K key, long milliseconds, ExpireArgs expireArgs);

    /**
     * Set a key's time to live in milliseconds.
     *
     * @param key the key.
     * @param milliseconds the milliseconds.
     * @return integer-reply, specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not exist or
     *         the timeout could not be set.
     * @since 6.1
     */
    RedisFuture<Boolean> pexpire(K key, Duration milliseconds);

    /**
     * Set a key's time to live in milliseconds.
     *
     * @param key the key.
     * @param milliseconds the milliseconds.
     * @param expireArgs the expiry arguments.
     * @return integer-reply, specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not exist or
     *         the timeout could not be set.
     * @since 6.2
     */
    RedisFuture<Boolean> pexpire(K key, Duration milliseconds, ExpireArgs expireArgs);

    /**
     * Set the expiration for a key as a UNIX timestamp specified in milliseconds.
     *
     * @param key the key.
     * @param timestamp the milliseconds-timestamp type: posix time.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set (see: {@code EXPIRE}).
     */
    RedisFuture<Boolean> pexpireat(K key, long timestamp);

    /**
     * Set the expiration for a key as a UNIX timestamp specified in milliseconds.
     *
     * @param key the key.
     * @param timestamp the milliseconds-timestamp type: posix time.
     * @param expireArgs the expiry arguments.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set (see: {@code EXPIRE}).
     * @since 6.2
     */
    RedisFuture<Boolean> pexpireat(K key, long timestamp, ExpireArgs expireArgs);

    /**
     * Set the expiration for a key as a UNIX timestamp specified in milliseconds.
     *
     * @param key the key.
     * @param timestamp the milliseconds-timestamp type: posix time.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set (see: {@code EXPIRE}).
     */
    RedisFuture<Boolean> pexpireat(K key, Date timestamp);

    /**
     * Set the expiration for a key as a UNIX timestamp specified in milliseconds.
     *
     * @param key the key.
     * @param timestamp the milliseconds-timestamp type: posix time.
     * @param expireArgs the expiry arguments.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set (see: {@code EXPIRE}).
     * @since 6.2
     */
    RedisFuture<Boolean> pexpireat(K key, Date timestamp, ExpireArgs expireArgs);

    /**
     * Set the expiration for a key as a UNIX timestamp specified in milliseconds.
     *
     * @param key the key.
     * @param timestamp the milliseconds-timestamp type: posix time.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set (see: {@code EXPIRE}).
     */
    RedisFuture<Boolean> pexpireat(K key, Instant timestamp);

    /**
     * Set the expiration for a key as a UNIX timestamp specified in milliseconds.
     *
     * @param key the key.
     * @param timestamp the milliseconds-timestamp type: posix time.
     * @param expireArgs the expiry arguments.
     * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not
     *         exist or the timeout could not be set (see: {@code EXPIRE}).
     * @since 6.2
     */
    RedisFuture<Boolean> pexpireat(K key, Instant timestamp, ExpireArgs expireArgs);

    /**
     * Get the time to live for a key in as unix timestamp in milliseconds.
     *
     * @param key the key.
     * @return Long integer-reply in milliseconds, or a negative value in order to signal an error. The command returns
     *         {@code -1} if the key exists but has no associated expiration time. The command returns {@code -2} if the key
     *         does not exist.
     * @since 6.2
     */
    RedisFuture<Long> pexpiretime(K key);

    /**
     * Get the time to live for a key in milliseconds.
     *
     * @param key the key.
     * @return Long integer-reply in milliseconds, or a negative value in order to signal an error. The command returns
     *         {@code -1} if the key exists but has no associated expiration time. The command returns {@code -2} if the key
     *         does not exist.
     */
    RedisFuture<Long> pttl(K key);

    /**
     * Return a random key from the keyspace.
     *
     * @return K bulk-string-reply the random key, or {@code null} when the database is empty.
     */
    RedisFuture<K> randomkey();

    /**
     * Rename a key.
     *
     * @param key the key.
     * @param newKey the newkey type: key.
     * @return String simple-string-reply.
     */
    RedisFuture<String> rename(K key, K newKey);

    /**
     * Rename a key, only if the new key does not exist.
     *
     * @param key the key.
     * @param newKey the newkey type: key.
     * @return Boolean integer-reply specifically:
     *
     *         {@code true} if {@code key} was renamed to {@code newkey}. {@code false} if {@code newkey} already exists.
     */
    RedisFuture<Boolean> renamenx(K key, K newKey);

    /**
     * Create a key using the provided serialized value, previously obtained using DUMP.
     *
     * @param key the key.
     * @param ttl the ttl type: long.
     * @param value the serialized-value type: string.
     * @return String simple-string-reply The command returns OK on success.
     */
    RedisFuture<String> restore(K key, long ttl, byte[] value);

    /**
     * Create a key using the provided serialized value, previously obtained using DUMP.
     *
     * @param key the key.
     * @param value the serialized-value type: string.
     * @param args the {@link RestoreArgs}, must not be {@code null}.
     * @return String simple-string-reply The command returns OK on success.
     * @since 5.1
     */
    RedisFuture<String> restore(K key, byte[] value, RestoreArgs args);

    /**
     * Sort the elements in a list, set or sorted set.
     *
     * @param key the key.
     * @return List&lt;V&gt; array-reply list of sorted elements.
     */
    RedisFuture<List<V>> sort(K key);

    /**
     * Sort the elements in a list, set or sorted set.
     *
     * @param channel streaming channel that receives a call for every value.
     * @param key the key.
     * @return Long number of values.
     */
    RedisFuture<Long> sort(ValueStreamingChannel<V> channel, K key);

    /**
     * Sort the elements in a list, set or sorted set.
     *
     * @param key the key.
     * @param sortArgs sort arguments.
     * @return List&lt;V&gt; array-reply list of sorted elements.
     */
    RedisFuture<List<V>> sort(K key, SortArgs sortArgs);

    /**
     * Sort the elements in a list, set or sorted set.
     *
     * @param channel streaming channel that receives a call for every value.
     * @param key the key.
     * @param sortArgs sort arguments.
     * @return Long number of values.
     */
    RedisFuture<Long> sort(ValueStreamingChannel<V> channel, K key, SortArgs sortArgs);

    /**
     * Sort the elements in a list, set or sorted set.
     *
     * @param key the key.
     * @return List&lt;V&gt; array-reply list of sorted elements.
     * @since 6.2
     */
    RedisFuture<List<V>> sortReadOnly(K key);

    /**
     * Sort the elements in a list, set or sorted set.
     *
     * @param channel streaming channel that receives a call for every value.
     * @param key the key.
     * @return Long number of values.
     * @since 6.2
     */
    RedisFuture<Long> sortReadOnly(ValueStreamingChannel<V> channel, K key);

    /**
     * Sort the elements in a list, set or sorted set.
     *
     * @param key the key.
     * @param sortArgs sort arguments.
     * @return List&lt;V&gt; array-reply list of sorted elements.
     * @since 6.2
     */
    RedisFuture<List<V>> sortReadOnly(K key, SortArgs sortArgs);

    /**
     * Sort the elements in a list, set or sorted set.
     *
     * @param channel streaming channel that receives a call for every value.
     * @param key the key.
     * @param sortArgs sort arguments.
     * @return Long number of values.
     * @since 6.2
     */
    RedisFuture<Long> sortReadOnly(ValueStreamingChannel<V> channel, K key, SortArgs sortArgs);

    /**
     * Sort the elements in a list, set or sorted set.
     *
     * @param key the key.
     * @param sortArgs sort arguments.
     * @param destination the destination key to store sort results.
     * @return Long number of values.
     */
    RedisFuture<Long> sortStore(K key, SortArgs sortArgs, K destination);

    /**
     * Touch one or more keys. Touch sets the last accessed time for a key. Non-exsitent keys wont get created.
     *
     * @param keys the keys.
     * @return Long integer-reply the number of found keys.
     */
    RedisFuture<Long> touch(K... keys);

    /**
     * Get the time to live for a key.
     *
     * @param key the key.
     * @return Long integer-reply TTL in seconds, or a negative value in order to signal an error. The command returns
     *         {@code -1} if the key exists but has no associated expiration time. The command returns {@code -2} if the key
     *         does not exist.
     */
    RedisFuture<Long> ttl(K key);

    /**
     * Determine the type stored at key.
     *
     * @param key the key.
     * @return String simple-string-reply type of {@code key}, or {@code none} when {@code key} does not exist.
     */
    RedisFuture<String> type(K key);

    /**
     * Incrementally iterate the keys space.
     *
     * @return KeyScanCursor&lt;K&gt; scan cursor.
     */
    RedisFuture<KeyScanCursor<K>> scan();

    /**
     * Incrementally iterate the keys space. Use {@link KeyScanArgs} to specify {@code SCAN}-specific arguments.
     *
     * @param scanArgs scan arguments.
     * @return KeyScanCursor&lt;K&gt; scan cursor.
     * @see KeyScanArgs
     */
    RedisFuture<KeyScanCursor<K>> scan(ScanArgs scanArgs);

    /**
     * Incrementally iterate the keys space. Use {@link KeyScanArgs} to specify {@code SCAN}-specific arguments.
     *
     * @param scanCursor cursor to resume from a previous scan, must not be {@code null}.
     * @param scanArgs scan arguments.
     * @return KeyScanCursor&lt;K&gt; scan cursor.
     * @see KeyScanArgs
     */
    RedisFuture<KeyScanCursor<K>> scan(ScanCursor scanCursor, ScanArgs scanArgs);

    /**
     * Incrementally iterate the keys space.
     *
     * @param scanCursor cursor to resume from a previous scan, must not be {@code null}.
     * @return KeyScanCursor&lt;K&gt; scan cursor.
     */
    RedisFuture<KeyScanCursor<K>> scan(ScanCursor scanCursor);

    /**
     * Incrementally iterate the keys space.
     *
     * @param channel streaming channel that receives a call for every key.
     * @return StreamScanCursor scan cursor.
     */
    RedisFuture<StreamScanCursor> scan(KeyStreamingChannel<K> channel);

    /**
     * Incrementally iterate the keys space. Use {@link KeyScanArgs} to specify {@code SCAN}-specific arguments.
     *
     * @param channel streaming channel that receives a call for every key.
     * @param scanArgs scan arguments.
     * @return StreamScanCursor scan cursor.
     * @see KeyScanArgs
     */
    RedisFuture<StreamScanCursor> scan(KeyStreamingChannel<K> channel, ScanArgs scanArgs);

    /**
     * Incrementally iterate the keys space. Use {@link KeyScanArgs} to specify {@code SCAN}-specific arguments.
     *
     * @param channel streaming channel that receives a call for every key.
     * @param scanCursor cursor to resume from a previous scan, must not be {@code null}.
     * @param scanArgs scan arguments.
     * @return StreamScanCursor scan cursor.
     * @see KeyScanArgs
     */
    RedisFuture<StreamScanCursor> scan(KeyStreamingChannel<K> channel, ScanCursor scanCursor, ScanArgs scanArgs);

    /**
     * Incrementally iterate the keys space.
     *
     * @param channel streaming channel that receives a call for every key.
     * @param scanCursor cursor to resume from a previous scan, must not be {@code null}.
     * @return StreamScanCursor scan cursor.
     */
    RedisFuture<StreamScanCursor> scan(KeyStreamingChannel<K> channel, ScanCursor scanCursor);

}
